import { Component, ViewChild } from '@angular/core';
import { Subject } from 'rxjs/internal/Subject';
import { deepClone, getO, getText, getValueUsingField, missing, replaceAll, type } from '../../../utils/utils';
import { of } from 'rxjs/internal/observable/of';
import { catchError, debounceTime, distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators';
import { ApiService } from '@core/services/http/api.service';
import { ExpressionService } from '@core/services/expression/ExpressionService';
import { SearchService } from '@core/services/search.service';
import { NgSelectComponent } from '@shared/apes/ng-select';
import { ICellEditorAngularComp } from '@ag-grid-community/angular';

@Component({
  selector: 'apes-cell-select',
  template: `
    <ng-select
      [items]="itemsData"
      #select
      style="height:100%"
      [ngStyle]="{'width': dropDownWidth+'px' }"
      class="apes-ng-select"
      [disabled]="getDisabled()"
      [placeholder]="placeholder()"
      [(ngModel)]="inputValue"
      [loading]="isLoading"
      [virtualScroll]="true"
      [searchBtn]="_searchBtn"
      [typeahead]="searchInput$"
      [searchable]="_ShowSearch"
      (close)="onBackFillData($event)"
      (searchBtnFn)="onSearch()"
      (scrollToEnd)="fetchMore()"
      [multiple]="multiple"
      [groupBy]="showGroupBy(itemsData)"
      (keydown)="onKeyDown($event)">
      <ng-template ng-label-tmp let-item="item" let-clear="clear">
        <span class="ng-value-label">{{formatter(item, getValueFormatter())}}</span>
        <span class="ng-value-icon right" (click)="clear(item)" aria-hidden="true">×</span>
      </ng-template>
      <ng-template ng-optgroup-tmp let-item="item" let-index="index">
        <ng-container>
          {{item[groupBy]}}
        </ng-container>
      </ng-template>
      <ng-template ng-option-tmp let-item="item">
        {{formatter(item, getDownFormatter())}}
      </ng-template>
    </ng-select>
  `,
  styles: [],
})
export class EditorSelectComponent implements ICellEditorAngularComp {

  inputValue: any;
  params: any;
  apesConfig: any;
  ctx: any;
  options = [];
  callbackBody: any;
  data: any;
  cellDisabled = false;
  searchFormId: string;
  searchSelectApi: string;
  _ShowSearch = true;
  _searchBtn = false;
  private _current = 0;
  multiple = false;
  width = 0;
  isLoading = false;
  private _pages = 0;
  private _searchText = '';
  contractLoading = false;
  itemsData: any = [];
  searchInput$ = new Subject<string>();
  private _domain;
  groupBy: any;
  dropDownWidth: any = 0;

  @ViewChild(NgSelectComponent, { static: true })
  private select: NgSelectComponent;

  constructor(private apiService: ApiService, private expressionService: ExpressionService, protected searchService: SearchService) {
    this.loadData();
  }

  agInit(params: any): void {
    this.params = params;
    this.inputValue = params.value;
    this.ctx = params.context;
    this.apesConfig = this.extend(params);
    this.apesConfig = { ...this.apesConfig, ...params['column']['colDef'] };
    this.callbackBody = this.apesConfig.callback;

    this.width = this.params.width;
    this.searchFormId = this.params.searchFormId;
    this.searchSelectApi = this.params.api;
    this.multiple = this.params.column.colDef.multiple === 'true' || false;
    if (this.apesConfig.hasOwnProperty('dropDownWidth')) {
      this.dropDownWidth = this.apesConfig.dropDownWidth;
    } else {
      this.dropDownWidth = this.params.column.actualWidth;
    }
    if (this.params['domain']) {
      this.params.domain = replaceAll(this.params.domain, '\'', '');
      this._domain = JSON.parse(this.params.domain);
    }
    if (this.params['searchFormId']) {
      this._searchBtn = true;
    }
    if (this.params['items']) {
      this.itemsData = getO(this.params['items']);
      this._ShowSearch = false;
    }

    // 用于不搜索，数据无法删除功能 和items = []配合使用
    if (this.apesConfig['showSearch']) {
      this.searchInput$ = null;
    }

    if (this.apesConfig['init'] && this.apesConfig['items']) {
      this.itemsData = getO(this.apesConfig['items']);
      this._ShowSearch = false;
    }
    if (this.apesConfig['init'] && this.apesConfig['api'] && !this.apesConfig['items']) {
      this.getItemData();
    }

    if (this.params.hasOwnProperty('colDef')) {
      this.data = this.params.data;
      if (this.params.colDef.hasOwnProperty('cellEditorDisabled')) {
        this.cellDisabled = !this.expressionService.eval(this.params.colDef.cellEditorDisabled, {
          context: this.ctx,
          form: this.ctx.form,
          model: this.ctx.model,
          data: this.data,
        });
      }
    } else {
      this.data = this.params.node.data;
    }
  }

  extend(data: any) {
    let result = {};
    for (let key in data) {
      let value = data[key];
      if (key === 'context') {
        result['ctx'] = value;
      } else {
        result[key] = value;
      }
    }
    return result;
  }

  ngAfterViewInit() {
    setTimeout(() => {
      this.select.focus();
    }, 500);
  }

  isPopup(): boolean {
    setTimeout(() => {
      this.select.open();
    }, 50);
    return true;
  }

  onBackFillData(params: any) {
    this.params.value = params;
    // this.params.column.gridApi.tabToNextCell();
    this.params.column.gridApi.stopEditing(false);
  }

  getValue(): any {
    let result;
    if (this.inputValue == null || this.inputValue == undefined) {
      result = null;
      this.params.value = null;
    } else {
      result = this.inputValue;
      this.params.value = this.inputValue;
    }
    return result;
  }

  // refresh(params: any): boolean {
  //     return undefined;
  // }

  onKeyDown(event): void {
    let key = event.which || event.keyCode;
    if (key === 38 || key === 40) {
      this.preventDefaultAndPropagation(event);

      if (key == 38) {
      } else if (key == 40) {
      }
    }
  }

  private preventDefaultAndPropagation(event) {
    event.preventDefault();
    event.stopPropagation();
  }

  getDisabled() {
    return this.cellDisabled || false;
  }

  placeholder() {
    return this.params.placeholder || '';
  }

  private loadData() {
    this.searchInput$.pipe(
      debounceTime(500),
      distinctUntilChanged(),
      tap(() => this.contractLoading = true),
      switchMap((term) => {
        if (missing(term)) {
          this.contractLoading = false;
          return of([]);
        }
        if (this._searchText === term) return of([]);
        this._current = 0;
        this._searchText = term;
        const data = this.getApiParams();
        return this.apiService.post(this.searchSelectApi, data).pipe(
          map((res) => {
              this.itemsData = [];
              this._searchText = term;
              this.itemsData = this.itemsData.concat(res.content);
              this._current = res.page + 1;
              this._pages = res.pages;
              return res.content;
            },
          ),
          catchError(() => of([])), // empty list on error
          tap(() => this.contractLoading = false),
        );
      }),
    ).subscribe();
  }


  fetchMore() {
    this.contractLoading = true;
    // using timeout here to simulate backend API delay
    // if (this._current === this._pages || this._searchText === '')
    if (this._current === this._pages) {
      this.contractLoading = false;
      return;
    }
    this.getItemData();
  }

  getItemData() {
    const data = this.getApiParams();
    this.apiService.post(this.searchSelectApi, data).subscribe(item => {
      this.contractLoading = false;
      if (item.page === 0) {
        this.itemsData = [];
      }
      this.itemsData = this.itemsData.concat(item.content);
      this._current = item.page + 1;
      this._pages = item.pages;
    });
  }

  onSearch() {
    const key = '1'; //this.to.componentRef.field.key;
    var cModel;
    if (this.searchFormId.indexOf('strategy.') >= 0) {
      cModel = {};
    } else {
      cModel = { ...this.ctx['model'], node: this.params.node['data'] };
    }
    const options = {
      multiple: this.multiple,
      conditionModel: cModel,
    }; // 声明查询条件
    if (this._domain) {
      const group = this.fillField(this._domain, true);
      console.log(JSON.stringify(group));
      if (!(group.filters.length === 0 && group.groups.length === 0)) {
        options['domain'] = group;
      }
    }
    if (this.apesConfig.uniqueKey) {
      options['uniqueKey'] = this.apesConfig.uniqueKey;
      options['addSame'] = this.apesConfig.addSame != 'false';
    }
    // 弹窗api与下拉api保持一致
    options['api'] = this.searchSelectApi;
    this.searchService.openDialog(this.searchFormId, options, (result: any) => {
      if (result && result.length > 0 || typeof result == 'object') {
        let key = this.params.column.colId;
        if (this.callbackBody) {
          this.expressionService.evaluate(this.callbackBody, {
            context: this.ctx,
            form: this.ctx.form,
            model: this.ctx.model,
            value: result,
            data: this.data,
          }, true);
        } else {
          this.itemsData = [];
          if (typeof result == 'object') {
            this.itemsData = [...result];
          } else {
            for (let i = 0, len = result.length; i < len; i++) {
              this.itemsData = this.itemsData.concat(result[i]);
            }
          }
          if (this.multiple) {
            if (this.params[key] !== null && this.params[key] !== undefined) {
              const items = deepClone(this.params[key]);
              this.itemsData = items.concat(this.itemsData);
            }
            this.params.node.setDataValue(key, this.itemsData);
            this.inputValue = this.itemsData;
          } else {
            this.params.node.setDataValue(key, this.itemsData[0]);
            this.inputValue = this.itemsData[0];
          }
        }
      }
    }).subscribe();
  }

  getValueFormatter(): string {
    return this.apesConfig.valueFormatter || 'value.name';
  }

  getDownFormatter(): string {
    return this.apesConfig.downFormatter || '\'[ \' + value.id + \' ]\' + \' \' + value.name';
  }

  getApiParams() {
    const data = { key: this._searchText, page: this._current, size: 20 };
    if (this._domain) {
      const group = this.fillField(this._domain);
      data['group'] = group;
    }
    return data;
  }

  // 对传入的域进行处理
  private fillField(domain: any, searchFlag: Boolean = false) {
    let result;
    if (type(domain) === 'object') {
      result = {};
    } else {
      result = [];
    }
    for (const key in domain) {
      let value = domain[key];
      const t = type(value);
      if (t === 'object') {
        value = this.fillField(value, searchFlag);
      } else if (t === 'array') {
        value = [...this.fillField(value, searchFlag)];
      } else {
        if (t === 'string') {
          const text = getText(value);
          if (text) {
            if (text === 'value') {
              if (searchFlag) return;
              value = this._searchText;
            } else if (text.indexOf('grid.') == 0) { // 监听表格域规则
              // debugger;
              let field = text.slice(5);
              value = getValueUsingField(this.params.node.data, field, true);
            } else {
              value = getValueUsingField(this.ctx, text, true);
            }
          }

        }
      }

      let val = value;
      if (type(value) === 'array') {
        if (type(val) === 'array') {
          // 对解析出的数据做出筛选
          val = val.filter((elem) => elem !== undefined);
        }
        value = val;
      } else if (type(value) === 'object' && val && val.filters) {
        if (val.filters.length === 0) {
          if (val.groups.length === 0) {
            val = [];
          } else {
            val.filters = val.groups;
            val.groups = [];
          }
        }
      }

      if (key === 'groups' && val[0] && val[0].length === 0) {
        result[key] = [];
      } else {
        result[key] = val;
      }
    }

    return result;
  }

  formatter(value: any, expression: string) {
    return this.expressionService.evaluate(expression, {
      context: this.params.context,
      model: this.params.context,
      value: value,
    });
  }

  showGroupBy(items) {
    let check = false;
    let groupBy = '';
    if (items != undefined && items.length != 0) {
      items.forEach((item) => {
        if (item.hasOwnProperty('groupBy')) {
          check = true;
          groupBy = item.groupBy;
        }
      });
    }
    if (check) {
      this.groupBy = groupBy;
      return groupBy;
    } else {
      return false;
    }
  }

  clickClear() {
    this.inputValue = null;
  }
}
